#ifndef FILESYS_INODE_H
#define FILESYS_INODE_H

#include <stdbool.h>
#include "filesys/off_t.h"
#include "devices/disk.h"
// 3 idiots added begin
#include <list.h>
#include "threads/synch.h"
// 3 idiots added end

// 3 idiots added begin
#define DIRECT_DISK_SECTOR_SIZE 122
#define INDIRECT_DISK_SECTOR_SIZE 128
#define SQUARED_INDIRECT_DISK_SECTOR_SIZE 128 * 128 // 8MB
#define DIR_INDIR_DISK_SECTOR_SIZE DIRECT_DISK_SECTOR_SIZE + INDIRECT_DISK_SECTOR_SIZE
#define ALL_LINKED_DISK_SECTOR_SIZE DIR_INDIR_DISK_SECTOR_SIZE + SQUARED_INDIRECT_DISK_SECTOR_SIZE
// 3 idiots added end

struct bitmap;

enum inode_type 
{
    INODE_FILE,
    INODE_DIR
};

// 3 idiots added begin
struct inode_disk
{
    enum inode_type id_type;
    off_t id_length;
    unsigned id_sec_cnt;								
    unsigned id_magic_num;                     						
    disk_sector_t dir_disk_sector_list[DIRECT_DISK_SECTOR_SIZE];
    disk_sector_t indir_disk_sector;
    disk_sector_t squared_indir_disk_sector;
};

struct indir_disk_sector
{
    disk_sector_t dir_disk_sector_list[INDIRECT_DISK_SECTOR_SIZE];
};
// 3 idiots added end

/* In-memory inode. */
struct inode 
{
    struct list_elem elem;              /* Element in inode list. */
    disk_sector_t sector;               /* Sector number of disk location. */
    int open_cnt;                       /* Number of openers. */
    bool removed;                       /* True if deleted, false otherwise. */
    int deny_write_cnt;                 /* 0: writes ok, >0: deny writes. */
    struct inode_disk data;             /* Inode content. */
};

void inode_init (void);
bool inode_create (disk_sector_t, off_t, bool);
struct inode *inode_open (disk_sector_t);
struct inode *inode_reopen (struct inode *);
disk_sector_t inode_get_inumber (const struct inode *);
void inode_close (struct inode *);
void inode_remove (struct inode *);
off_t inode_read_at (struct inode *, void *, off_t size, off_t offset);
off_t inode_write_at (struct inode *, const void *, off_t size, off_t offset);
void inode_deny_write (struct inode *);
void inode_allow_write (struct inode *);
off_t inode_length (const struct inode *);

bool inode_grow (struct inode*, off_t);
void inode_new_sector (struct inode*, disk_sector_t);
void inode_make_empty (struct inode *inode);
struct indir_disk_sector* inode_create_indir_disk_sector (disk_sector_t);
struct inode_disk* inode_create_disk (disk_sector_t);
void inode_initialize_disk_inode (struct inode_disk*, disk_sector_t, off_t, bool);
bool inode_is_dir (const struct inode* inode);
void inode_read_or_write_empty (disk_sector_t, void*, bool);
void inode_read_or_write (disk_sector_t, void*, off_t, bool);

#endif /* filesys/inode.h  */
